﻿/**	@file		post_list.hpp
 *	@date		(2012-07-07 18:27:32)/(2012-07-07 18:27:33)
 *-----------------------------------------------------------------------------
 *	\brief		在多个县城间单方面交换信息的列表.
 *	@version	1.0.1.1
 *	@author		Nick Shallery	(nicknide@gmail.com)
 *	@copyright	YOU HAVE ALL LEFT WITH THIS CODE WHILE YOU KEEP COMMENT IN EVERY COPY.
 *-----------------------------------------------------------------------------
**/

#if			!defined(__LOLIX__LOLI__POST_LIST__HPP__NICK__K_IN_G__)
#define		__LOLIX__LOLI__POST_LIST__HPP__NICK__K_IN_G__

#if			!defined(__LOLIX__TOY_ALLOCATOR__K_IN_G__)
	#include	"../toy/allocator.h"
#endif	//	!defined(__LOLIX__TOY_ALLOCATOR__K_IN_G__)

#if			!defined(__LOLIX__LOLI_X_CFG__K_IN_G__)
	#include	"../toy/std_v2t.hpp"
#endif	//	!defined(__LOLIX__LOLI_X_CFG__K_IN_G__)

#if			!defined(__LOLIX__LOLI__LOCKED_OPERATOR__NICK__K_IN_G__)
	#include	"./locked_operator.h"
#endif	//	!defined(__LOLIX__LOLI__LOCKED_OPERATOR__NICK__K_IN_G__)

namespace lolix{namespace loli{
	template<typename _Ty, bool _IsOrdered = true, typename _Tsig = void, typename _Talc = lolix::toy::allocator<void> >
	class post_list;
}}


template<typename _Ty, bool _IsOrdered, typename _Tsig, typename _Talc>
class lolix::loli::post_list
	: public toy::v2t_trait<_Ty>
{
	CANNT_COPY_LOLI;
	struct _Tblock
	{
		LOLIX_INLINE_CALL _Tblock(void){}
		LOLIX_INLINE_CALL _Tblock(_Ty const& tv):_val(tv){}
#if			LOLIX_CFG__SUPPORT_CPP_0X
		LOLIX_INLINE_CALL _Tblock(_Ty&& tv):_val(lolix::forward<_Ty>(tv)){}
#endif	//	LOLIX_CFG__SUPPORT_CPP_0X
		_Ty			_val;
		_Tblock*	_next;
	};
	typedef typename _Talc::rebind_type<_Tblock>::others	allocator_type;
	_Tblock*			_start;
	_Tblock*			_read_list;
	locked_operator*	_locker;
	allocator_type		_alc;

public:
	LOLIX_INLINE_CALL post_list(locked_operator* locker)
		: _locker(locker)
		, _read_list(0)
		, _start(0)
		{
		_locker->inc_ref();
		}

	LOLIX_INLINE_CALL ~post_list(void)
		{
		_Tblock* start = _start;
		while ( start )
			{
			_Tblock* val = start;
			start = start->_next;
			_alc.destroy(val);
			_alc.deallocate(val);
			}
		_locker->release();
		}

	LOLIX_INLINE_CALL push(_Ty const& tv)
		{
		_Tblock* ptr = _alc.allocate(1);
		_alc.construct(ptr, tv);
		__Push_ptr(ptr);
		}

#if			LOLIX_CFG__SUPPORT_CPP_0X
	LOLIX_INLINE_CALL push(_Ty&& tv)
		{
		auto* ptr = _alc.allocate(1);
		_alc.construct(ptr, forward<_Ty>(tv));
		__Push_ptr(ptr);
		}
#endif	//	LOLIX_CFG__SUPPORT_CPP_0X

	LOLIX_INLINE_CALL bool pop(_Ty& out)
		{
		_Tblock* start = __Pop_ptr();
		if ( !start )
			return false;
#if			LOLIX_CFG__SUPPORT_CPP_0X
		out = forward<_Ty>(start->_val);
#else	//	LOLIX_CFG__SUPPORT_CPP_0X
		lolix::discard_copy(out, start->_val);
#endif	//	LOLIX_CFG__SUPPORT_CPP_0X
		_alc.destory(start);
		_alc.deallocate(start, 1);
		}

private:
	LOLIX_INLINE_CALL __Push_ptr(_Tblock* ptr)
		{
		_Tblock* next ;
		do
			{
			next = _start;
			ptr->_next = next;
			}
		while ( _locker->chg_ptr(&_start, ptr, next) == ptr );
		}

	LOLIX_INLINE_CALL _Tblock* __Pop_ptr(void)
		{
		if ( _read_list )
			{
			_Tblock* cur = _read_list;
			_read_list = _read_list->_next;
			return 0;
			}

		_Tblock* cur;
		do
			cur = _start;
		while ( _locker->chg_ptr(&_start, 0, cur) != cur );

		//	may be need revert list??
		if ( _IsOrdered )
			{
			_Tblock* next = cur->_next;
			while ( next )
				{
				_Tblock* tmp = next->_next;
				next->_next = cur;
				cur = next;
				next = tmp;
				}
			}

		_read_list = cur->_next;
		return cur;
		}
}



#endif	//	!defined(__LOLIX__LOLI__POST_LIST__HPP__NICK__K_IN_G__)
